home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / packer / tar / src / port.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  13KB  |  554 lines

  1. /*
  2.  * @(#)port.c 1.15    87/11/05    Public Domain, by John Gilmore, 1986
  3.  *
  4.  * These are routines not available in all environments.
  5.  *
  6.  * I know this introduces an extra level of subroutine calls and is
  7.  * slightly slower.  Frankly, my dear, I don't give a damn.  Let the
  8.  * Missed-Em Vee losers suffer a little.  This software is proud to
  9.  * have been written on a BSD system.
  10.  */
  11. #ifdef AMIGA
  12. #include <stdlib.h>
  13. #endif
  14.  
  15. #include <stdio.h>
  16. #include <sys/types.h>
  17. #include <sys/stat.h>
  18. #include <signal.h>
  19. #include <errno.h>
  20.  
  21. #if defined(MSDOS) || defined(AMIGA)
  22. #include <fcntl.h>
  23. #else
  24. #include <sys/file.h>
  25. #endif
  26.  
  27. #include "tar.h"
  28.  
  29. extern char **environ;
  30.  
  31. #ifndef NULL
  32. #define NULL 0
  33. #endif
  34.  
  35. /*
  36.  * Some people (e.g. V7) don't have a #define for these.
  37.  */
  38. #ifndef    O_BINARY
  39. #define    O_BINARY    0
  40. #endif
  41. #ifndef    O_RDONLY
  42. #define    O_RDONLY    0
  43. #endif
  44.  
  45.  
  46. #include "port.h"
  47.  
  48.  
  49. /*
  50.  * Some computers are not so crass as to align themselves into the BSD
  51.  * or USG camps.  If a system supplies all of the routines we fake here,
  52.  * add it to the list in the #ifndefs below and it'll all be skipped.
  53.  * Make sure to add a matching #endif at the end of the file!
  54.  *
  55.  * We are avoiding #if defined() here for the sake of Minix, which comes
  56.  * with the severely broken Amsterdam Compiler Kit.  Thanks, Andy!
  57.  */
  58. #ifndef mc300
  59. #ifndef mc500
  60. #ifndef mc700
  61.  
  62.  
  63. #ifndef BSD42
  64. /*
  65.  * lstat() is a stat() which does not follow symbolic links.
  66.  * If there are no symbolic links, just use stat().
  67.  */
  68. int
  69. lstat (path, buf)
  70.     char *path;
  71.     struct stat *buf;
  72. {
  73.     extern int stat ();
  74.     return (stat (path, buf));
  75. }
  76.  
  77. /*
  78.  * valloc() does a malloc() on a page boundary.  On some systems,
  79.  * this can make large block I/O more efficient.
  80.  */
  81. char *
  82. valloc (size)
  83.     unsigned size;
  84. {
  85. #ifndef AMIGA
  86.     extern char *malloc ();
  87. #endif
  88.     return (malloc (size));
  89. }
  90.  
  91. /*
  92.  *                NMKDIR.C
  93.  *
  94.  * Written by Robert Rother, Mariah Corporation, August 1985. 
  95.  *
  96.  * I wrote this out of shear disgust with myself because I couldn't
  97.  * figure out how to do this in /bin/sh.
  98.  *
  99.  * If you want it, it's yours.  All I ask in return is that if you
  100.  * figure out how to do this in a Bourne Shell script you send me
  101.  * a copy.
  102.  *                    sdcsvax!rmr or rmr@uscd
  103. *
  104. * Severely hacked over by John Gilmore to make a 4.2BSD compatible
  105. * subroutine.    11Mar86; hoptoad!gnu
  106. *
  107. * Modified by rmtodd@uokmax 6-28-87 -- when making an already existing dir,
  108. * subroutine didn't return EEXIST.  It does now.
  109. */
  110.  
  111. /*
  112.  * Make a directory.  Compatible with the mkdir() system call on 4.2BSD.
  113.  */
  114. #if !defined(MSDOS) && !defined(AMIGA)
  115. int
  116. mkdir(dpath, dmode)
  117.     char *dpath;
  118.     int dmode;
  119. {
  120.     int cpid, status;
  121.     struct stat statbuf;
  122.     extern int errno;
  123.  
  124.     if (stat(dpath,&statbuf) == 0) {
  125.         errno = EEXIST;        /* Stat worked, so it already exists */
  126.         return -1;
  127.     }
  128.  
  129.     /* If stat fails for a reason other than non-existence, return error */
  130.     if (errno != ENOENT) return -1; 
  131.  
  132.     switch (cpid = fork()) {
  133.  
  134.     case -1:            /* Error in fork() */
  135.         return(-1);        /* Errno is set already */
  136.  
  137.     case 0:                /* Child process */
  138.         /*
  139.          * Cheap hack to set mode of new directory.  Since this
  140.          * child process is going away anyway, we zap its umask.
  141.          * FIXME, this won't suffice to set SUID, SGID, etc. on this
  142.          * directory.  Does anybody care?
  143.          */
  144.         status = umask(0);    /* Get current umask */
  145.         status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
  146.         execl("/bin/mkdir", "mkdir", dpath, (char *)0);
  147.         _exit(-1);        /* Can't exec /bin/mkdir */
  148.     
  149.     default:            /* Parent process */
  150.         while (cpid != wait(&status)) ;    /* Wait for kid to finish */
  151.     }
  152.  
  153.     if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
  154.         errno = EIO;        /* We don't know why, but */
  155.         return -1;        /* /bin/mkdir failed */
  156.     }
  157.  
  158.     return 0;
  159. }
  160. #endif    /* MSDOS */
  161. #endif
  162.  
  163. /* This next bit is called "doing OR on Minix cpp", e.g. without defined(). */
  164. #undef WANTSTRING
  165. #ifdef USG
  166. #define WANTSTRING
  167. #endif
  168. #ifdef MSDOS
  169. #define WANTSTRING
  170. #endif
  171. #ifdef AMIGA
  172. #define WANTSTRING
  173. #endif
  174.  
  175. #ifdef WANTSTRING
  176. /*
  177.  * Translate V7 style into Sys V style.
  178.  */
  179. #include <string.h>
  180. #ifndef AMIGA
  181. #include <memory.h>
  182. #endif
  183.  
  184. char *
  185. index (s, c)
  186.     char *s;
  187.     int c;
  188. {
  189.     return (strchr (s, c));
  190. }
  191.  
  192. void
  193. bcopy (s1, s2, n)
  194.     char *s1, *s2;
  195.     int n;
  196. {
  197.     (void) memcpy (s2, s1, n);
  198. }
  199.  
  200. void
  201. bzero (s1, n)
  202.     char *s1;
  203.     int n;
  204. {
  205.     (void) memset(s1, 0, n);
  206. }
  207.  
  208. int
  209. bcmp(s1, s2, n)
  210.     char    *s1, *s2;
  211.     int    n;
  212. {
  213.     return memcmp(s1, s2, n);
  214. }
  215. #endif
  216.  
  217. #ifdef MINIX
  218. /* Minix has bcopy but not bzero, and no memset.  Thanks, Andy. */
  219. void
  220. bzero (s1, n)
  221.     register char *s1;
  222.     register int n;
  223. {
  224.     while (n--) *s1++ = '\0';
  225. }
  226.  
  227. /* It also has no bcmp() */
  228. int
  229. bcmp (s1, s2, n) 
  230.     register char *s1,*s2;
  231.     register int n;
  232. {
  233.     for ( ; n-- ; ++s1, ++s2) {
  234.         if (*s1 != *s2) return *s1 - *s2;
  235.     }
  236.     return 0;
  237. }
  238.  
  239. /*
  240.  * Groan, Minix doesn't have execlp either!
  241.  *
  242.  * execlp(file,arg0,arg1...argn,(char *)NULL)
  243.  * exec a program, automatically searching for the program through
  244.  * all the directories on the PATH.
  245.  *
  246.  * This version is naive about variable argument lists, it assumes
  247.  * a straightforward C calling sequence.  If your system has odd stacks
  248.  * *and* doesn't have execlp, YOU get to fix it.
  249.  */
  250. int
  251. execlp(filename, arg0)
  252.     char *filename, *arg0;
  253. {
  254.     extern char *malloc(), *getenv(), *index();
  255.     extern int errno;
  256.     register char *p, *path;    
  257.     char **argstart = &arg0;
  258.     register char *fnbuffer;
  259.     struct stat statbuf;
  260.  
  261.     if ((p = getenv("PATH")) == NULL) {
  262.         /* couldn't find path variable -- try to exec given filename */
  263.         return execve(filename, argstart, environ);
  264.     }
  265.  
  266.     /*
  267.      * make a place to build the filename.  We malloc larger than we
  268.      * need, but we know it will fit in this.
  269.      */
  270.     fnbuffer = malloc( strlen(p) + 1 + strlen(filename) );
  271.     if (fnbuffer == NULL) {
  272.         errno = ENOMEM;
  273.         return -1;
  274.     }
  275.  
  276.     /*
  277.      * try each component of the path to see if the file's there
  278.      * and executable.
  279.      */
  280.     for (path = p ; path ; path = p) {
  281.         /* construct full path name to try */
  282.         if ((p = index(path,':')) == NULL) {
  283.             strcpy(fnbuffer, path);
  284.         } else {
  285.             strncpy(fnbuffer, path, p-path);
  286.             fnbuffer[p-path] = '\0';
  287.             p++;        /* Skip : for next time */
  288.         }
  289.         if (strlen(fnbuffer) != 0)
  290.             strcat(fnbuffer,"/");
  291.         strcat(fnbuffer,filename);
  292.  
  293.         /* check to see if file is there and is a normal file */
  294.         if (stat(fnbuffer, &statbuf) < 0) {
  295.             if (errno == ENOENT)
  296.                 continue; /* file not there,keep on looking */
  297.             else
  298.                 goto fail; /* failed for some reason, return */
  299.         }
  300.         if ( (statbuf.st_mode & S_IFMT) != S_IFREG) continue;
  301.  
  302.         if (execve(fnbuffer, argstart, environ) < 0
  303.             && errno != ENOENT
  304.             && errno != ENOEXEC) {
  305.             /* failed, for some other reason besides "file
  306.              * not found" or "not a.out format"
  307.              */
  308.             goto fail;
  309.         }
  310.  
  311.         /*
  312.          * If we got error ENOEXEC, the file is executable but is
  313.          * not an object file.  Try to execute it as a shell script,
  314.          * returning error if we can't execute /bin/sh.
  315.          *
  316.          * FIXME, this code is broken in several ways.  Shell
  317.          * scripts should not in general be executed by the user's
  318.          * SHELL variable program.  On more mature systems, the
  319.          * script can specify with #!/bin/whatever.  Also, this
  320.          * code clobbers argstart[-1] if the exec of the shell
  321.          * fails.
  322.          */
  323.         if (errno == ENOEXEC) {
  324.             char *shell;
  325.  
  326.             /* Try to execute command "sh arg0 arg1 ..." */
  327.             if ((shell = getenv("SHELL")) == NULL)
  328.                 shell = "/bin/sh";
  329.             argstart[-1] = shell;
  330.             argstart[0] = fnbuffer;
  331.             execve(shell, &argstart[-1], environ);
  332.             goto fail;    /* Exec didn't work */
  333.         }
  334.  
  335.         /* 
  336.          * If we succeeded, the execve() doesn't return, so we
  337.          * can only be here is if the file hasn't been found yet.
  338.          * Try the next place on the path.
  339.          */
  340.     }
  341.  
  342.     /* all attempts failed to locate the file.  Give up. */
  343.     errno = ENOENT;
  344.  
  345. fail:
  346.     free(fnbuffer);
  347.     return -1;
  348. }
  349. #endif /* MINIX */
  350.  
  351.  
  352. #ifdef EMUL_OPEN3
  353. #include "open3.h"
  354. /*
  355.  * open3 -- routine to emulate the 3-argument open system
  356.  * call that is present in most modern Unix systems.
  357.  * This version attempts to support all the flag bits except for O_NDELAY
  358.  * and O_APPEND, which are silently ignored.  The emulation is not as efficient
  359.  * as the real thing (at worst, 4 system calls instead of one), but there's
  360.  * not much I can do about that.
  361.  *
  362.  * Written 6/10/87 by rmtodd@uokmax
  363.  *
  364.  * open3(path, flag, mode)
  365.  * Attempts to open the file specified by
  366.  * the given pathname.  The following flag bits (#defined in tar.h)
  367.  * specify options to the routine:
  368.  *    O_RDONLY    file open for read only
  369.  *    O_WRONLY    file open for write only
  370.  *    O_RDWR        file open for both read & write
  371.  * (Needless to say, you should only specify one of the above).
  372.  *     O_CREAT        file is created with specified mode if it needs to be.
  373.  *    O_TRUNC        if file exists, it is truncated to 0 bytes
  374.  *    O_EXCL        used with O_CREAT--routine returns error if file exists
  375.  * Function returns file descriptor if successful, -1 and errno if not.
  376.  */
  377.  
  378. /*
  379.  * array to give arguments to access for various modes
  380.  * FIXME, this table depends on the specific integer values of O_XXX,
  381.  * and also contains integers (args to 'access') that should be #define's.
  382.  */
  383. static int modes[] =
  384.     {
  385.         04, /* O_RDONLY */
  386.         02, /* O_WRONLY */
  387.         06, /* O_RDWR */
  388.         06, /* invalid but we'd better cope -- O_WRONLY+O_RDWR */
  389.     };
  390.  
  391. /* Shut off the automatic emulation of open(), we'll need it. */
  392. #undef open
  393.  
  394. int
  395. open3(path, flags, mode)
  396. char *path;
  397. int flags, mode;
  398. {
  399.     extern int errno;
  400.     int exists = 1;
  401.     int call_creat = 0;
  402.     int fd;
  403.     /*
  404.      * We actually do the work by calling the open() or creat() system
  405.      * call, depending on the flags.  Call_creat is true if we will use 
  406.      * creat(), false if we will use open().
  407.      */
  408.  
  409.     /*
  410.      * See if the file exists and is accessible in the requested mode. 
  411.      *
  412.      * Strictly speaking we shouldn't be using access, since access checks
  413.      * against real uid, and the open call should check against euid.
  414.      * Most cases real uid == euid, so it won't matter.   FIXME.
  415.      * FIXME, the construction "flags & 3" and the modes table depends
  416.      * on the specific integer values of the O_XXX #define's.  Foo!
  417.      */
  418.     if (access(path,modes[flags & 3]) < 0) {
  419.         if (errno == ENOENT) {
  420.             /* the file does not exist */
  421.             exists = 0;
  422.         } else {
  423.             /* probably permission violation */
  424.             if (flags & O_EXCL) {
  425.                 /* Oops, the file exists, we didn't want it. */
  426.                 /* No matter what the error, claim EEXIST. */
  427.                 errno = EEXIST;
  428.             }
  429.             return -1;
  430.         }
  431.     }
  432.  
  433.     /* if we have the O_CREAT bit set, check for O_EXCL */
  434.     if (flags & O_CREAT) {
  435.         if ((flags & O_EXCL) && exists) {
  436.             /* Oops, the file exists and we didn't want it to. */
  437.             errno = EEXIST;
  438.             return -1;
  439.         }
  440.         /*
  441.          * If the file doesn't exist, be sure to call creat() so that
  442.          * it will be created with the proper mode.
  443.          */
  444.         if (!exists) call_creat = 1;
  445.     } else {
  446.         /* If O_CREAT isn't set and the file doesn't exist, error. */
  447.         if (!exists) {
  448.             errno = ENOENT;
  449.             return -1;
  450.         }
  451.     }
  452.  
  453.     /*
  454.      * If the O_TRUNC flag is set and the file exists, we want to call
  455.      * creat() anyway, since creat() guarantees that the file will be
  456.      * truncated and open()-for-writing doesn't.
  457.      * (If the file doesn't exist, we're calling creat() anyway and the
  458.      * file will be created with zero length.)
  459.      */
  460.     if ((flags & O_TRUNC) && exists) call_creat = 1;
  461.     /* actually do the call */
  462.     if (call_creat) {
  463.         /*
  464.          * call creat.  May have to close and reopen the file if we
  465.          * want O_RDONLY or O_RDWR access -- creat() only gives
  466.          * O_WRONLY.
  467.          */
  468.         fd = creat(path,mode);
  469.         if (fd < 0 || (flags & O_WRONLY)) return fd;
  470.         if (close(fd) < 0) return -1;
  471.         /* Fall out to reopen the file we've created */
  472.     }
  473.  
  474.     /*
  475.      * calling old open, we strip most of the new flags just in case.
  476.      */
  477.     return open(path, flags & (O_RDONLY|O_WRONLY|O_RDWR|O_BINARY));
  478. }
  479. #endif
  480.  
  481. #endif /* MASSCOMP mc700 */
  482. #endif /* MASSCOMP mc500 */
  483. #endif /* MASSCOMP mc300 */
  484.  
  485.  
  486.  
  487. #if defined(MSDOS) || defined(AMIGA)
  488. /* Fake mknod by complaining */
  489. int
  490. mknod(path, mode, dev)
  491.     char        *path;
  492.     unsigned short    mode;
  493.     dev_t        dev;
  494. {
  495.     extern int    errno;
  496.     int        fd;
  497.     
  498.     errno = ENXIO;        /* No such device or address */
  499.     return -1;        /* Just give an error */
  500. }
  501.  
  502. /* Fake links by copying */
  503. int
  504. link(path1, path2)
  505.     char        *path1;
  506.     char        *path2;
  507. {
  508.     char    buf[256];
  509.     int    ifd, ofd;
  510.     int    nrbytes;
  511.     int    nwbytes;
  512.  
  513.     fprintf(stderr, "%s: %s: cannot link to %s, copying instead\n",
  514.         tar, path1, path2);
  515.     if ((ifd = open(path1, O_RDONLY|O_BINARY)) < 0)
  516.         return -1;
  517.     if ((ofd = creat(path2, 0666)) < 0)
  518.         return -1;
  519. #ifdef MSDOS
  520.     setmode(ofd, O_BINARY);
  521. #endif
  522.     while ((nrbytes = read(ifd, buf, sizeof(buf))) > 0) {
  523.         if ((nwbytes = write(ofd, buf, nrbytes)) != nrbytes) {
  524.             nrbytes = -1;
  525.             break;
  526.         }
  527.     }
  528.     /* Note use of "|" rather than "||" below: we want to close
  529.      * the files even if an error occurs.
  530.      */
  531.     if ((nrbytes < 0) | (0 != close(ifd)) | (0 != close(ofd))) {
  532.         unlink(path2);
  533.         return -1;
  534.     }
  535.     return 0;
  536. }
  537.  
  538. /* everyone owns everything on MS-DOS (or is it no one owns anything?) */
  539. int
  540. chown(path, uid, gid)
  541.     char    *path;
  542.     int    uid;
  543.     int    gid;
  544. {
  545.     return 0;
  546. }
  547.  
  548. int
  549. geteuid()
  550. {
  551.     return 0;
  552. }
  553. #endif    /* MSDOS */
  554.